package Model;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/**
 * 
 * A játéktér legfontosabb feladata a mezők és a dinamikus entitások tárolása (a mezőkön keresztül pedig a rajtuk tartózkodó entitások összességét.
 * A játéktér gyakorlatilag egy globális kép a játék aktuális állásáról, illetve előkészíti a legközelebbi kaja megtalálásához szükséges információkat,
 * azaz hogy melyik mezőre lépve jutunk közelebb a legközelebbi ételhez (ez alapesetben egyszer történik meg: a játék kezdetén).
 * Emellett lebonyolítja a játékköröket, és menedzseli a nyilvántartásra szoruló entitásokat.
 *
 */

public class Jatekter implements INyilvantarto
{
	private ArrayList<Kaja> kajak;
	
	/** Tárolja a Játéktérben lévő összes Mezőt. */
	private ArrayList<MozgoDinEntitas> mozgoEntitasok;

	/** Tárolja a Játéktérben található összes mozgó Entitást.*/
	private ArrayList<NemMozgoDinEntitas> nemMozgoEntitasok;

	/** Tárolja a Játéktérben található összes nem mozgó, de gondolkodó Entitást. */
	private ArrayList<Mezo> mezoLista = new ArrayList<Mezo>();
	
	private int szelesseg, magassag;
	
	public static int szagspray, olospray;
	
	static
	{
		szagspray = 22;
		olospray = 22;
	}
	
	/**
	 * A Jatekter osztály default konstruktora, melyben a listák inicializálásra kerülnek.
	 */
	
	public Jatekter(int _szelesseg, int _magassag)
	{
		szelesseg = _szelesseg;
		magassag = _magassag;
		
		kajak = new ArrayList<Kaja>();
		mozgoEntitasok = new ArrayList<MozgoDinEntitas>();
		nemMozgoEntitasok = new ArrayList<NemMozgoDinEntitas>();
		mezoLista = new ArrayList<Mezo>();
		
		for (int i = 0; i < szelesseg*magassag; i++)
		{
			// letrehozzuk a megfelelo szamu mezot
			mezoLista.add(new Mezo());
		}
		
		if(szelesseg==2 && magassag==1)
		{			
			for(int j=0;j<2;j++)
			{
				ArrayList<Mezo> szomszedok = new ArrayList<Mezo>();
				for(int i=0;i<6;i++)
					szomszedok.add(mezoLista.get((j+1)%2));
				mezoLista.get(j).setSzomszedMezok(szomszedok);
			}
			
			return;
		}
			
		
		for (int i = 0; i < szelesseg*magassag; i++) { // beadjuk a szomszedokat
			ArrayList<Mezo> sz = mezoLista.get(i).getSzomszedok();
			/* 
			 k adiknak:

			felso szomszedja: k-szelesseg*2
			also szomszedja: k+szelesseg*2

			paros sorokban ( 0 tol kezdjuk a szamolast ):
			k+szelesseg es a k+szelesseg+1 edik a bal also es a jobb also szomszedai
			k-szelesseg es a k-szelesseg+1 edik a bal felso es a jobb felso szomszedai

			paratlan sorokban:
			k-szelesseg es a k-szelesseg-1 edik a jobb felso es a bal felso szomszedai
			k+szelesseg es a k+szelesseg-1 edik a jobb also es a bal also szomszedai
			0: felso
			1: jobb felso
			2: jobb also
			3: also
			4: bal also
			5: bal felso
			*/
			
			Mezo felso = null;
			Mezo jobbFelso = null;
			Mezo jobbAlso = null;
			Mezo also = null;
			Mezo balAlso = null;
			Mezo balFelso = null;
			
			int m = szelesseg*magassag;
			
			//felso szomszed beallitasa
			if(i-szelesseg*2>=0 )
				felso = mezoLista.get(i-szelesseg*2);
			//also szomszed beallitasa
			if(i+szelesseg*2<m)
				also = mezoLista.get(i+szelesseg*2);
			
			
			
			if((i/szelesseg)%2 == 0) {//ha paros a sor
				
				// eleg azt nezni, hogy kivul esik-e ugyanis soha nem lesz a palya szelen
				if(i+szelesseg<m)
					balAlso = mezoLista.get(i+szelesseg);
				if(i-szelesseg>=0)
					balFelso = mezoLista.get(i-szelesseg);
					
				// ha nem a jobb szelen vagyunk
				if((i+1)%szelesseg != 0) {
					
					// es beleesunk a tombbe
					if(i+szelesseg+1<m)
						jobbAlso = mezoLista.get(i+szelesseg+1);
					if(i-szelesseg+1>=0)
						jobbFelso = mezoLista.get(i-szelesseg+1);
				}
				
				
			} else {//ha paratlan a sor
				// ez mindig van
				jobbFelso = mezoLista.get(i-szelesseg);
				if(i+szelesseg<m) // ha nem esik kivul
					jobbAlso = mezoLista.get(i+szelesseg);
				
				if(i%szelesseg != 0) { // ha nem bal szelen vagyunk
					balFelso = mezoLista.get(i-szelesseg-1); //felso mindig van
					if(i+szelesseg-1<m) // ha belul vagyunk
						balAlso = mezoLista.get(i+szelesseg-1);
				}
				
			}
			
			
			sz.add(felso);
			sz.add(jobbFelso);
			sz.add(jobbAlso);
			sz.add(also);
			sz.add(balAlso);
			sz.add(balFelso);
			
			mezoLista.get(i).setSzomszedMezok(sz);
		}
		
	}

	public int getMagassag()
	{
		return magassag;
	}

	public int getSzelesseg()
	{
		return szelesseg;
	}
	
	public void addKaja(Kaja k)
	{
		kajak.add(k);
	}
	
	/**
	 * Minden egyes Mezőre kiszámolkja hogy arról a Mezőről melyik szomszédos Mezőre kell lépni ahhoz,
	 * hogy közelebb kerüljünk a legközelebbi Kajához.
	 */
	public void legkozelebbiKajaKitolto()
	{

		for (Mezo mezo : mezoLista)
		{
			int min;
			Mezo merre;
			//majd minden egyes elemre
			if(mezo.getSzomszedok().get(0) == null) {// ha felfele nincs mezo legyen lefele
				min = milyenmesszevaninnenkaja(mezo.getSzomszedok().get(3));
				merre = mezo.getSzomszedok().get(3);
			}
			else {// ha van mezo felfele
				min = milyenmesszevaninnenkaja(mezo.getSzomszedok().get(0));
				merre = mezo.getSzomszedok().get(0);
			}
			
			
			for (Mezo szomszed : mezo.getSzomszedok()) {
				if(szomszed != null) {
				if(milyenmesszevaninnenkaja(szomszed) < min) {
					min = milyenmesszevaninnenkaja(szomszed);
					merre = szomszed;
				}
				}
			}
			
			mezo.setLegkozelebbiKajaIranya(merre);
			
		}

	}
	
	
	
	/** megnezi, hogy milyen messze van a legkozelebbi kaja m hez
	*/
	private int milyenmesszevaninnenkaja(Mezo m) {
	
		Set<Mezo> kajak = new HashSet<Mezo>();// egy lista a mezokrol ahol kaja van
		for (Kaja kaja : this.kajak) {
			kajak.add(kaja.holvagyok());
		}
		
		Set<Mezo> h = new HashSet<Mezo>();
		h.add(m); // belerakom az elso mezot
		
		if(kajak.isEmpty()) return 0;
		
		int tavolsag = 0;
		while(true)
		{
			Set<Mezo> szomszedokkal = new HashSet<Mezo>();
			szomszedokkal.addAll(h);
			for (Mezo mezo : h) {
				if(mezo != null) {
				for (Mezo me : mezo.getSzomszedok()) {
					szomszedokkal.add(me);
				}
				}
			}
			
			h.retainAll(kajak);
			if(!h.isEmpty()) {
				return tavolsag;
			}
			
			h = szomszedokkal;
			tavolsag++;
			
		}
	}
	
	
	

	/**
	 * Megfelelő sorrendben meghívja a tárolt Entitások tick függvényét.
	 */
	public void jatekkor()
	{
		for(int i = 0, prevSize = mozgoEntitasok.size(); i < mozgoEntitasok.size(); i++)
		{
			mozgoEntitasok.get(i).tick();
			if(prevSize > mozgoEntitasok.size()) i--;
			prevSize = mozgoEntitasok.size();
		}
		
		for(int i = 0, prevSize = nemMozgoEntitasok.size(); i < nemMozgoEntitasok.size(); i++)
		{
			nemMozgoEntitasok.get(i).tick();
			if(prevSize > nemMozgoEntitasok.size()) i--;
			prevSize = nemMozgoEntitasok.size();
		}
	}

	/**
	 * Hozzáadja az adminisztrációs listához a paraméterben kapott objektumot.
	 * @param e Egy NemMozgoDinEntitas objektum.
	 */
	public void feliratkozas(NemMozgoDinEntitas e)
	{
		nemMozgoEntitasok.add(e);
	}

	/**
	 * Leveszi az adminisztrációs listáról a paraméterben kapott objektumot.
	 * @param e Egy NemMozgoDinEntitas objektum.
	 */
	public void leiratkozas(NemMozgoDinEntitas e)
	{
		nemMozgoEntitasok.remove(e);
	}

	/**
	 * Hozzáadja az adminisztrációs listához a paraméterben kapott objektumot.
	 * @param e Egy MozgoDinEntitas objektum.
	 */
	public void feliratkozas(MozgoDinEntitas e)
	{
		mozgoEntitasok.add(e);
	}

	/**
	 * Leveszi az adminisztrációs listáról a paraméterben kapott objektumot.
	 * @param e Egy MozgoDinEntitas objektum.
	 */
	public void leiratkozas(MozgoDinEntitas e)
	{
		mozgoEntitasok.remove(e);
	}
	
	/**
	 * Kizárólag a tesztelési fázisban szükséges függvény.
	 * @return A Játéktérben lévő Mezők listája.
	 */
	public ArrayList<Mezo> getMezoLista()
	{
		return mezoLista;
	}
	
	public ArrayList<NemMozgoDinEntitas> getNemMozgoDinEntitasok() {
		return nemMozgoEntitasok;
	}
	
	public ArrayList<MozgoDinEntitas> getMozgoDinEntitasok() {
		return mozgoEntitasok;
	}
}